#pragma once

#include "opencv2/opencv.hpp"
#include "opencv2/core/matx.hpp"
#include "opencv2\imgproc\types_c.h"
#include <vector>
#include <Windows.h>
// #include "read.h"
using namespace cv;

namespace SL
{
    typedef std::vector<Point2f> Corners;
    typedef std::vector<Corners> CornersList;
    typedef std::vector<Point3f> Points;
    using Color = std::array<unsigned char, 3>;
    typedef std::vector<Color> Colors;
    typedef std::vector<Mat> Images;
    typedef std::vector<Images> ImagesList;
    struct ImageWithParam
    {
        Mat image;
        int height;
        int width;
        std::string filename;
    };
    struct Extrinsic
    {
        Mat matrix;
        Mat rotation;
        Vec3f translation;
        Mat fundamental;
        Mat essential;
    };

    struct Intrinsic
    {
        Mat matrix;
        float fx;
        float fy;
        float tx;
        float ty;
        std::vector<float> kc;
        double error;
    };

    struct ProjectorCalibrateTrinsics
    {
        Extrinsic extrinsic;
        Intrinsic cameraIntrinsic;
        Intrinsic projectorIntrinsic;
    };

    struct BiocularCalibrateTrinsics
    {
        Extrinsic extrinsic;
        Intrinsic leftIntrinsic;
        Intrinsic rightIntrinsic;
    };

    class SlContent
    {

    public:
        std::vector<SL::ImageWithParam *> patternImagesWithParam;
        std::vector<SL::ImageWithParam *> cameraImagesWithParam;
        std::vector<std::vector<SL::ImageWithParam *>> cameraImagesWithParamList;
        int patternImageNo;
        int cameraImageNo;
        CornersList cameraCornersList;
        Points worldCooridnates;
        // Extrinsic extrinsic;
        // Intrinsic cameraIntrinsic;
        // Intrinsic projectorIntrinsic;

        Images cameraImages()
        {
            Images images;
            for (int i = 0; i < cameraImagesWithParam.size(); i++)
            {
                images.push_back(cameraImagesWithParam[i]->image);
            }
            return images;
        }

        Images cameraImages(int id)
        {
            Images images;
            for (int i = 0; i < cameraImagesWithParamList[id].size(); i++)
            {
                images.push_back(cameraImagesWithParamList[id][i]->image);
            }
            return images;
        }

        Images cameraGrayImages()
        {
            if (this->_cameraGrayImages.size() != 0)
            {
                return this->_cameraGrayImages;
            }
            Images images;
            for (int i = 0; i < cameraImagesWithParam.size(); i++)
            {
                Mat grayImage;
                grayImage = cameraImagesWithParam[i]->image;
                // extractChannel(cameraImagesWithParam[i]->image, grayImage, 0);
                // cvtColor(cameraImagesWithParam[i]->image, grayImage, CV_BGR2GRAY);
                // grayImage = cameraImagesWithParam[i]->image;
                images.push_back(grayImage);
                // std::string filename = "D:\\code\\amiraSl\\test\\gray\\" + std::to_string(i) + ".png";
                // imwrite(filename, grayImage);
            }
            return images;
        }
        Images cameraGrayImages(int id)
        {
            Images images;
            for (int i = 0; i < cameraImagesWithParamList[id].size(); i++)
            {
                Mat grayImage;
                // grayImage = cameraImagesWithParamList[id][i]->image;
                extractChannel(cameraImagesWithParamList[id][i]->image, grayImage, 0);
                // cvtColor(cameraImagesWithParamList[id][i]->image, grayImage, CV_BGR2GRAY);
                images.push_back(grayImage);
            }
            return images;
        }
        Images patternImages()
        {
            Images images;
            for (int i = 0; i < patternImagesWithParam.size(); i++)
            {
                images.push_back(patternImagesWithParam[i]->image);
            }
            return images;
        }

    private:
        Images _cameraImages;
        Images _patternImages;
        Images _cameraGrayImages;
    };

    class SLContent
    {
    public:
        static SLContent &getInstance()
        {
            static SLContent instance;
            return instance;
        }
        SlContent &getContent()
        {
            return this->content;
        }

    private:
        SLContent(){};
        SLContent(SLContent &) = delete;
        void operator=(SLContent const &) = delete;
        SlContent content;
    };
};